# !/usr/bin/env python
# -*-coding:utf-8 -*-

"""
# File       : vm_agent.py
# Time       ：2025/5/27 17:59
# Description：
"""

from typing import Optional, List
from datetime import datetime
from enum import IntEnum
from pydantic import BaseModel, validator, ValidationError



# GameStatus enum
class GameStatus(IntEnum):
    GameStatusAllocInitial = 0
    GameStatusAllocSuccess = 1
    GameStatusAllocQueuing = 2
    GameStatusAllocFailure = 3
    GameStatusStartSuccess = 4
    GameStatusStartProcing = 5
    GameStatusStartFailure = 6
    GameStatusCloseSuccess = 7
    GameStatusUserInActive = 8
    GameStatusUserUnActive = 9
    GameStatusAllocPrepare = 11
    GameStatusIdleClosed = 12
    GameStatusHoldClosed = 13
    GameStatusReadyRender = 17


# GameEvent enum for internal mapping
class GameEvent(IntEnum):
    GameEventArchiveInit = 0
    GameEventArchiveInitFail = 1
    GameEventArchiveInitSuccess = 2
    GameEventDownload = 3
    GameEventDownloadFail = 4
    GameEventDownloadSuccess = 5
    GameEventDeploy = 6
    GameEventDeployFail = 7
    GameEventDeploySuccess = 8
    GameEventUnload = 9
    GameEventUnloadFail = 10
    GameEventUnloadSuccess = 11
    GameEventUpload = 12
    GameEventUploadFail = 13
    GameEventUploadSuccess = 14
    GameEventRecover = 15
    GameEventRecoverFail = 16
    GameEventRecoverSuccess = 17
    GameEventCallGsmStartGameSuccess = 18
    GameEventCallGsmStartGameFailure = 19
    GameEventCallGsmEndGameSuccess = 20
    GameEventCallGsmEndGameFailure = 21


game_event_to_string = {
    GameEvent.GameEventArchiveInit: "GameEventArchiveInit",
    GameEvent.GameEventArchiveInitFail: "GameEventArchiveInitFail",
    GameEvent.GameEventArchiveInitSuccess: "GameEventArchiveInitSuccess",
    GameEvent.GameEventDownload: "GameEventDownload",
    GameEvent.GameEventDownloadFail: "GameEventDownloadFail",
    GameEvent.GameEventDownloadSuccess: "GameEventDownloadSuccess",
    GameEvent.GameEventDeploy: "GameEventDeploy",
    GameEvent.GameEventDeployFail: "GameEventDeployFail",
    GameEvent.GameEventDeploySuccess: "GameEventDeploySuccess",
    GameEvent.GameEventUnload: "GameEventUnload",
    GameEvent.GameEventUnloadFail: "GameEventUnloadFail",
    GameEvent.GameEventUnloadSuccess: "GameEventUnloadSuccess",
    GameEvent.GameEventUpload: "GameEventUpload",
    GameEvent.GameEventUploadFail: "GameEventUploadFail",
    GameEvent.GameEventUploadSuccess: "GameEventUploadSuccess",
    GameEvent.GameEventRecover: "GameEventRecover",
    GameEvent.GameEventRecoverFail: "GameEventRecoverFail",
    GameEvent.GameEventRecoverSuccess: "GameEventRecoverSuccess",
    GameEvent.GameEventCallGsmStartGameSuccess: "GameEventCallGsmStartGameSuccess",
    GameEvent.GameEventCallGsmStartGameFailure: "GameEventCallGsmStartGameFailure",
    GameEvent.GameEventCallGsmEndGameSuccess: "GameEventCallGsmEndGameSuccess",
    GameEvent.GameEventCallGsmEndGameFailure: "GameEventCallGsmEndGameFailure",
}

string_to_game_event = {v: k for k, v in game_event_to_string.items()}


# Pydantic models
class GameEventModel(BaseModel):
    value: str

    @validator('value')
    def validate_event(cls, v):
        if v not in string_to_game_event:
            raise ValueError(f"Invalid GameEvent string: {v}")
        return v


class CallGsmStartGameInfo(BaseModel):
    vpad_total: Optional[int] = 1
    vpad_id: Optional[int] = 1
    vpad_info: Optional[str] = "{\"1\":1,\"2\":0,\"3\":0,\"4\":0}"
    session_info: Optional[str] = "{\"a_session_id\":\"owmGnxBMgVjd\",\"v_session_id\":\"q375cK0xGITp\",\"c_session_id\":\"AuREvgXh5Eav\"}"
    rtc_data: Optional[str] = ""


class ArchiveFile(BaseModel):
    filePath: str
    fileSize: int
    status: str


class ArchiveInfo(BaseModel):
    id: int
    archiveFiles: List[ArchiveFile]
    archiveSize: int


class NotifyExtra(BaseModel):
    ArchiveInfo: Optional[ArchiveInfo] = None
    historicalEvents: List['CgVmAgentGameEventNotify'] = []

    class Config:
        alias_generator = lambda field_name: field_name
        allow_population_by_field_name = True


class StartGameReq(BaseModel):
    uid: Optional[str] = None
    gid: Optional[str] = None
    streamIpv4Address: Optional[str] = None
    vmid: Optional[int] = None
    uuid: Optional[str] = None
    ugid: Optional[str] = None
    extraParam: Optional[str] = None
    devId: Optional[str] = None
    vpadId: Optional[str] = None
    devType: Optional[int] = None
    streamInfo: Optional[str] = None
    startFlag: Optional[int] = None
    debugGameInfo: Optional[bool] = None
    asParam: Optional[str] = None
    sessionId: Optional[str] = None
    areaType: Optional[int] = None
    flowId: Optional[str] = None
    runtimeInfo: Optional[str] = None
    bizType: Optional[int] = None
    wallpaperAddr: Optional[str] = None
    imageVersion: Optional[str] = None
    idc: Optional[str] = None
    scheduleId: Optional[str] = None


class EndGameReq(BaseModel):
    uid: Optional[int] = None
    gid: Optional[int] = None
    vmid: Optional[int] = None
    flowId: Optional[str] = None
    areaType: Optional[int] = None
    asParam: Optional[str] = None
    bizType: Optional[int] = None
    debugGameInfo: Optional[bool] = None
    streamIpv4Address: Optional[str] = None
    scheduleId: Optional[str] = None


class Ret(BaseModel):
    code: int
    msg: str
    reason: str


class CgAgentResp(BaseModel):
    ret: Ret


class GsmGameStateNotify(BaseModel):
    detail: str = ""
    detailcode: int = 0
    gid: Optional[int] = None
    nonce: Optional[str] = None
    state: int
    timestamp: str = None
    uid: Optional[int] = None
    device_id: Optional[str] = None
    area_type: int = None
    vmid: Optional[int] = None


class CgVmAgentGameEventNotify(BaseModel):
    nonce: Optional[str] = None
    device_id: Optional[str] = None
    uid: Optional[int] = None
    vmid: Optional[int] = None
    gid: Optional[int] = None
    event: str
    timestamp: datetime
    msg: Optional[str] = None
    version: int
    extra: Optional[NotifyExtra] = None
    gsmStartGame: Optional[CallGsmStartGameInfo] = None
    scheduleId: Optional[str] = None



class GameStatus(IntEnum):
    GameStatusAllocInitial = 0
    GameStatusAllocSuccess = 1
    GameStatusAllocQueuing = 2
    GameStatusAllocFailure = 3
    GameStatusStartSuccess = 4
    GameStatusStartProcing = 5
    GameStatusStartFailure = 6
    GameStatusCloseSuccess = 7
    GameStatusUserInActive = 8
    GameStatusUserUnActive = 9
    GameStatusAllocPrepare = 11
    GameStatusIdleClosed = 12
    GameStatusHoldClosed = 13
    GameStatusReadyRender = 17


# GameEvent enum for internal mapping
class GameEvent(IntEnum):
    GameEventArchiveInit = 0
    GameEventArchiveInitFail = 1
    GameEventArchiveInitSuccess = 2
    GameEventDownload = 3
    GameEventDownloadFail = 4
    GameEventDownloadSuccess = 5
    GameEventDeploy = 6
    GameEventDeployFail = 7
    GameEventDeploySuccess = 8
    GameEventUnload = 9
    GameEventUnloadFail = 10
    GameEventUnloadSuccess = 11
    GameEventUpload = 12
    GameEventUploadFail = 13
    GameEventUploadSuccess = 14
    GameEventRecover = 15
    GameEventRecoverFail = 16
    GameEventRecoverSuccess = 17
    GameEventCallGsmStartGameSuccess = 18
    GameEventCallGsmStartGameFailure = 19
    GameEventCallGsmEndGameSuccess = 20
    GameEventCallGsmEndGameFailure = 21


game_event_to_string = {
    GameEvent.GameEventArchiveInit: "GameEventArchiveInit",
    GameEvent.GameEventArchiveInitFail: "GameEventArchiveInitFail",
    GameEvent.GameEventArchiveInitSuccess: "GameEventArchiveInitSuccess",
    GameEvent.GameEventDownload: "GameEventDownload",
    GameEvent.GameEventDownloadFail: "GameEventDownloadFail",
    GameEvent.GameEventDownloadSuccess: "GameEventDownloadSuccess",
    GameEvent.GameEventDeploy: "GameEventDeploy",
    GameEvent.GameEventDeployFail: "GameEventDeployFail",
    GameEvent.GameEventDeploySuccess: "GameEventDeploySuccess",
    GameEvent.GameEventUnload: "GameEventUnload",
    GameEvent.GameEventUnloadFail: "GameEventUnloadFail",
    GameEvent.GameEventUnloadSuccess: "GameEventUnloadSuccess",
    GameEvent.GameEventUpload: "GameEventUpload",
    GameEvent.GameEventUploadFail: "GameEventUploadFail",
    GameEvent.GameEventUploadSuccess: "GameEventUploadSuccess",
    GameEvent.GameEventRecover: "GameEventRecover",
    GameEvent.GameEventRecoverFail: "GameEventRecoverFail",
    GameEvent.GameEventRecoverSuccess: "GameEventRecoverSuccess",
    GameEvent.GameEventCallGsmStartGameSuccess: "GameEventCallGsmStartGameSuccess",
    GameEvent.GameEventCallGsmStartGameFailure: "GameEventCallGsmStartGameFailure",
    GameEvent.GameEventCallGsmEndGameSuccess: "GameEventCallGsmEndGameSuccess",
    GameEvent.GameEventCallGsmEndGameFailure: "GameEventCallGsmEndGameFailure",
}

string_to_game_event = {v: k for k, v in game_event_to_string.items()}


# Pydantic models
class GameEventModel(BaseModel):
    value: str

    @validator('value')
    def validate_event(cls, v):
        if v not in string_to_game_event:
            raise ValueError(f"Invalid GameEvent string: {v}")
        return v


class CallGsmStartGameInfo(BaseModel):
    vpad_total: Optional[int] = 1
    vpad_id: Optional[int] = 1
    vpad_info: Optional[str] = "{\"1\":1,\"2\":0,\"3\":0,\"4\":0}"
    session_info: Optional[str] = "{\"a_session_id\":\"owmGnxBMgVjd\",\"v_session_id\":\"q375cK0xGITp\",\"c_session_id\":\"AuREvgXh5Eav\"}"
    rtc_data: Optional[str] = ""


class ArchiveFile(BaseModel):
    filePath: str
    fileSize: int
    status: str


class ArchiveInfo(BaseModel):
    id: int
    archiveFiles: List[ArchiveFile]
    archiveSize: int


class NotifyExtra(BaseModel):
    ArchiveInfo: Optional[ArchiveInfo] = None
    historicalEvents: List['CgVmAgentGameEventNotify'] = []

    class Config:
        alias_generator = lambda field_name: field_name
        allow_population_by_field_name = True


class StartGameReq(BaseModel):
    uid: Optional[str] = None
    gid: Optional[str] = None
    streamIpv4Address: Optional[str] = None
    vmid: Optional[int] = None
    uuid: Optional[str] = None
    ugid: Optional[str] = None
    extraParam: Optional[str] = None
    devId: Optional[str] = None
    vpadId: Optional[str] = None
    devType: Optional[int] = None
    streamInfo: Optional[str] = None
    startFlag: Optional[int] = None
    debugGameInfo: Optional[bool] = None
    asParam: Optional[str] = None
    sessionId: Optional[str] = None
    areaType: Optional[int] = None
    flowId: Optional[str] = None
    runtimeInfo: Optional[str] = None
    bizType: Optional[int] = None
    wallpaperAddr: Optional[str] = None
    imageVersion: Optional[str] = None
    idc: Optional[str] = None
    scheduleId: Optional[str] = None


class EndGameReq(BaseModel):
    uid: Optional[int] = None
    gid: Optional[int] = None
    vmid: Optional[int] = None
    flowId: Optional[str] = None
    areaType: Optional[int] = None
    asParam: Optional[str] = None
    bizType: Optional[int] = None
    debugGameInfo: Optional[bool] = None
    streamIpv4Address: Optional[str] = None
    scheduleId: Optional[str] = None


class Ret(BaseModel):
    code: int
    msg: str
    reason: str


class CgAgentResp(BaseModel):
    ret: Ret


class GsmGameStateNotify(BaseModel):
    detail: str = ""
    detailcode: int = 0
    gid: Optional[int] = None
    nonce: Optional[str] = None
    state: int
    timestamp: str = None
    uid: Optional[int] = None
    device_id: Optional[str] = None
    area_type: int = None
    vmid: Optional[int] = None


class CgVmAgentGameEventNotify(BaseModel):
    nonce: Optional[str] = None
    device_id: Optional[str] = None
    uid: Optional[int] = None
    vmid: Optional[int] = None
    gid: Optional[int] = None
    event: str
    timestamp: datetime
    msg: Optional[str] = None
    version: int
    extra: Optional[NotifyExtra] = None
    gsmStartGame: Optional[CallGsmStartGameInfo] = None
    scheduleId: Optional[str] = None